package cn.itcast.bos.service.take_delivery.impl;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.index.query.QueryStringQueryBuilder.Operator;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.query.WildcardQueryBuilder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.itcast.bos.dao.index.WayBillIndexRepository;
import cn.itcast.bos.dao.take_delivery.WayBillRepository;
import cn.itcast.bos.domain.take_delivery.WayBill;
import cn.itcast.bos.service.take_delivery.WayBillService;

@Service
@Transactional
public class WayBillServiceImpl implements WayBillService {
	
	@Autowired
	private WayBillRepository wayBillRepository;
	
	@Autowired
	private WayBillIndexRepository wayBillIndexRepository;
	private static Logger logger = Logger.getLogger(WayBill.class);

	/**
	 * 保存运单的同时保存信息到ElasticSearch中
	 */
	@Override
	public void saveWayBill(WayBill wayBill) {
		WayBill persistwayBill = wayBillRepository.findByWayBillNum(wayBill.getWayBillNum());
		if(persistwayBill == null){
			//说明还没有该运单，设置运单状态，直接保存即可
			wayBill.setSignStatus(1);
			wayBillRepository.save(wayBill);
			//保存到ElasticSearch服务器
			wayBillIndexRepository.save(wayBill);
		}else{
			//说明已经存在相同的运单编号的运单(快速录入),跟新订单信息
			if(persistwayBill.getOrder() == null || persistwayBill.getOrder().getId() == null){
				if(persistwayBill.getSignStatus() == 1){
					Integer id = persistwayBill.getId();
					BeanUtils.copyProperties(wayBill, persistwayBill);
					persistwayBill.setId(id);
					persistwayBill.setSignStatus(2);
				}else{
					//说明已经存在的运单信息正在中转阶段，此时不可以修改运单的信息
					logger.info("正在流转的运单尝试更新运单，此项操作失败！");
					throw new RuntimeException();
				}
				//保存到ElasticSearch
				wayBillIndexRepository.save(persistwayBill);
				
			}
		}
	
	}

	//条件分页索引查询
	@Override
	public Page<WayBill> findByPage(WayBill wayBill,Pageable pages) {
		//因为页面加载的数据封装到datagried中，所以wayBill不为null，不用判断空
		//没有添加索引查询条件,查询数据库
		if(StringUtils.isBlank(wayBill.getWayBillNum())
				&& StringUtils.isBlank(wayBill.getRecAddress())
				&& StringUtils.isBlank(wayBill.getSendAddress())
				&& StringUtils.isBlank(wayBill.getSendProNum())
				&& (wayBill.getSignStatus() == null || wayBill.getSignStatus() == 0)){
			logger.info("分页数据库的查询");
			return wayBillRepository.findAll(pages);
		}else{
			BoolQueryBuilder query = new BoolQueryBuilder();
			if(StringUtils.isNotBlank(wayBill.getWayBillNum())){
				QueryBuilder q1 = new TermQueryBuilder("wayBillNum", wayBill.getWayBillNum());
				query.must(q1);
				logger.info("分页索引查询WayBillNum");
			}
			if(StringUtils.isNotBlank(wayBill.getRecAddress())){
				QueryBuilder q2 = new WildcardQueryBuilder("recAddress", "*"+wayBill.getRecAddress()+"*");
				/*
				 * 情况2：输入多字段查询
				 */
				QueryBuilder stringQueryBuilder = new QueryStringQueryBuilder(wayBill.getRecAddress())
						.field("recAddress").defaultOperator(Operator.AND);
				//两种情况取or
				BoolQueryBuilder queryBuilder = new BoolQueryBuilder();
				queryBuilder.should(q2);
				queryBuilder.should(stringQueryBuilder);
				
				query.must(q2);
				logger.info("分页多字段索引查询RecAddress");
				
			}
			if(StringUtils.isNotBlank(wayBill.getSendAddress())){
				QueryBuilder q3 = new WildcardQueryBuilder("sendAddress", "*"+wayBill.getSendAddress()+"*");
				query.must(q3);
				logger.info("分页索引查询SendAddress");
			}
			if(StringUtils.isNotBlank(wayBill.getSendProNum())){
				QueryBuilder q4 = new TermQueryBuilder("sendProNum", wayBill.getSendProNum());
				query.must(q4);
				logger.info("分页索引查询SendProNum");
			}
			if(wayBill.getSignStatus() != null && wayBill.getSignStatus() != 0){
				QueryBuilder q5 = new TermQueryBuilder("signStatus", wayBill.getSignStatus());
				query.must(q5);
				logger.info("分页索引查询SignStatus");
			}
			//添加分页条件
			SearchQuery searchQuery = new NativeSearchQuery(query);
			searchQuery.setPageable(pages);
			logger.info(searchQuery.getQuery().toString());
			//Page<WayBill> search = wayBillIndexRepository.search(query,pages);
			return wayBillIndexRepository.search(searchQuery);
		}
	}

	@Override
	public WayBill findByWayBillNum(String wayBillNum) {
		return wayBillRepository.findByWayBillNum(wayBillNum);
	}

	/**
	 * 用于定时跟新数据库和索引库的运单信息
	 */
	@Override
	public void updateIndex() {
		List<WayBill> wayBills = wayBillRepository.findAll();
		wayBillIndexRepository.save(wayBills);
		logger.info("数据库信息同步到服务器");
	}

	@Override
	public List<WayBill> exportFile(final WayBill wayBill) {
		//没有添加索引查询条件,查询数据库
		if(StringUtils.isBlank(wayBill.getWayBillNum())
				&& StringUtils.isBlank(wayBill.getRecAddress())
				&& StringUtils.isBlank(wayBill.getSendAddress())
				&& StringUtils.isBlank(wayBill.getSendProNum())
				&& (wayBill.getSignStatus() == null || wayBill.getSignStatus() == 0)){
			logger.info("无条件查询的运单导出数据");
			return wayBillRepository.findAll();
	}else{
			Specification<WayBill> specification = new Specification<WayBill>() {
				@Override
				public Predicate toPredicate(Root<WayBill> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
					ArrayList<Predicate> list = new ArrayList<>();
					if(StringUtils.isNotBlank(wayBill.getWayBillNum())){
						Predicate q1 = cb.equal(root.get("wayBillNum").as(String.class), wayBill.getWayBillNum());
						list.add(q1);
					}
					if(StringUtils.isNotBlank(wayBill.getSendAddress())){
						Predicate q2 = cb.like(root.get("sendAddress").as(String.class), "%"+wayBill.getSendAddress()+"%");
						list.add(q2);
					}
					if(StringUtils.isNotBlank(wayBill.getRecAddress())){
						Predicate q3 = cb.like(root.get("recAddress").as(String.class), "%"+wayBill.getRecAddress()+"%");
						list.add(q3);
					}
					if(StringUtils.isNotBlank(wayBill.getSendProNum())){
						Predicate q4 = cb.equal(root.get("sendProNum").as(String.class), wayBill.getSendProNum());
						list.add(q4);
					}
					if(wayBill.getSignStatus() != null && wayBill.getSignStatus() != 0){
						Predicate q5 = cb.equal(root.get("signStatus").as(Integer.class), wayBill.getSignStatus());
						list.add(q5);
					}
					return cb.and(list.toArray(new Predicate[0]));
				}
			};
			return wayBillRepository.findAll(specification);
		}
	}

}
